package cn.bytest.netty;

import cn.bytest.netty.code.NettyCodecAdapter;
import cn.bytest.netty.handler.ChannelRunnableHandler;
import cn.bytest.netty.handler.NettyServerHandler;
import cn.bytets.rpc.api.RpcServer;
import cn.bytets.rpc.common.utils.NamedTheadFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.apache.log4j.Logger;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;

import static java.util.concurrent.TimeUnit.SECONDS;

public class NettyServer extends AbstractCodecAdapter implements RpcServer{

    private Logger logger = Logger.getLogger(NettyServer.class);

    private ServerBootstrap server;

    private NioEventLoopGroup boot;

    private NioEventLoopGroup work;

    private Channel channel;

    private ThreadPoolExecutor executor;
    @Override
    public void start() {
        executor = new ThreadPoolExecutor(1,
                8, 30,
                SECONDS, new LinkedBlockingDeque<>(1000));
        server = new ServerBootstrap();
        boot = new NioEventLoopGroup(1, new NamedTheadFactory("NettyServerBoss",true));
        work = new NioEventLoopGroup(5, new NamedTheadFactory("NettyServerBoss",true));
        final NettyServerHandler nettyServerHandler = new NettyServerHandler(new ChannelRunnableHandler(executor));
        server.group(boot,work);
        server.channel(NioServerSocketChannel.class)
                //设置保持连接活动状态(childOption 这里是给接收通道添加的配置)
                .childOption(ChannelOption.TCP_NODELAY,Boolean.TRUE)
                .childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec());
                        ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
                                .addLast("server-idle-handler", new IdleStateHandler(0, 0, 180, SECONDS))
                                .addLast("decoder", adapter.getDecoder())
                                //.addLast("decoder", new StringDecoder())
                                .addLast("encoder", adapter.getEncoder())
                                //.addLast("encoder", new StringEncoder())
                                .addLast("handler", nettyServerHandler);
                    }
                });

        // bind
        ChannelFuture channelFuture = null;
        channelFuture = server.bind(8080);
        channelFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if(future.isSuccess()){
                    System.out.println("绑定端口成功");
                }
            }
        });
        //对关闭通道进行监听(只有关闭通道时才会进行处理)
        try {
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            stop();
        }

    }

    @Override
    public void stop() {
        try {
            if (channel != null) {
                // unbind.
                channel.close();
            }
        } catch (Throwable e) {
            logger.warn(e.getMessage(), e);
        }

        try {
            if (boot != null) {
                boot.shutdownGracefully();
                work.shutdownGracefully();
            }
        } catch (Throwable e) {
            logger.warn(e.getMessage(), e);
        }

    }

    @Override
    public boolean isAlive() {
        if (null==channel){
            return false;
        }
        return this.channel.isActive();
    }
}
